package com.chinaums.open.api.internal.util;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: ZHANGWEI
 * Date: 2016/12/2
 * Time: 16:17
 * 所属模块：
 * 功能说明：
 */
public class FieldUtils {
    public static Object getFieldValueByTypeAndFormat(Field field, Object bean,
                                                      String format) throws ParseException, IllegalArgumentException,
            IllegalAccessException {
        field.setAccessible(true);
        Object objValue = field.get(bean);
        Object ret = null;
        if (objValue == null)
            return ret;
        String type = field.getType().getName();
        if ("java.lang.String".equals(type)) {
            ret = field.get(bean).toString().trim();
        } else if ("java.lang.Integer".equals(type) || "int".equals(type)) {
            if (objValue instanceof Integer) {
                ret = ((Integer) objValue).toString();
            }
        } else if ("java.lang.Float".equals(type) || "float".equals(type)) {
            if (objValue instanceof Float) {
                ret = ((Float) objValue).toString();
            }
        } else if ("java.lang.Double".equals(type) || "double".equals(type)) {
            if (objValue instanceof Double) {
                ret = ((Double) objValue).toString();
            }
        } else if ("java.math.BigDecimal".equals(type)) {
            if (objValue instanceof BigDecimal) {
                ret = ((BigDecimal) objValue).toString();
            }
        } else if ("java.util.Date".equals(type)) {
            if (objValue instanceof Date) {
                Date dateValue = (Date) objValue;
                ret = new SimpleDateFormat(format).format(dateValue);
            }
        } else if ("java.lang.Boolean".equals(type)) {
            if (objValue instanceof Boolean) {
                ret = ((Boolean) objValue).toString();
            }
        } else if ("java.lang.Long".equals(type) || "long".equals(type)) {
            if (objValue instanceof Long) {
                ret = ((Long) objValue).toString();
            }
        } else {
            ret = objValue;
        }
        return ret;
    }

    public static void setFieldValueByType(Field field, Object bean,
                                           String value) throws IllegalArgumentException,
            IllegalAccessException, ParseException, ClassNotFoundException {
        setFieldValueByTypeAndFormat(field,bean,value,null);
    }

    public static void setFieldValueByTypeAndFormat(Field field, Object bean,
                                                    String value, String format) throws IllegalArgumentException,
            IllegalAccessException, ParseException, ClassNotFoundException {
        if (value == null)
            return;
        field.setAccessible(true);
        String type = field.getType().getName();
        if ("java.lang.String".equals(type)) {
            field.set(bean, value);
        } else if ("java.lang.Integer".equals(type)) {
            field.set(bean, Integer.valueOf(value));
        } else if ("int".equals(type)) {
            field.set(bean, Integer.valueOf(value).intValue());
        } else if ("java.lang.Float".equals(type)) {
            field.set(bean, Float.valueOf(value));
        } else if ("float".equals(type)) {
            field.set(bean, Float.valueOf(value).floatValue());
        } else if ("java.lang.Double".equals(type)) {
            field.set(bean, Double.valueOf(value));
        } else if ("double".equals(type)) {
            field.set(bean, Double.valueOf(value).doubleValue());
        } else if ("java.math.BigDecimal".equals(type)) {
            field.set(bean, new BigDecimal(value));
        } else if ("java.util.Date".equals(type)) {
            Date date = new SimpleDateFormat(format).parse(value.toString());
            field.set(bean, date);
        } else if ("java.lang.Boolean".equals(type)) {
            field.set(bean, Boolean.valueOf(value));
        } else if ("java.lang.Long".equals(type)) {
            field.set(bean, Long.valueOf(value));
        }  else if ("java.lang.Object".equals(type)) {
            field.set(bean, value);
        } else if ("long".equals(type)) {
            field.set(bean, Long.valueOf(value).longValue());
        } else if ("java.util.Map".equals(type)) {
            JSONObject mapObj = JSONObject.fromObject(value);
            field.set(bean,mapObj);
        } else if ("java.util.List".equals(type)) {
            JSONArray arr = JSONArray.fromObject(value);
            ParameterizedType genericType = (ParameterizedType) field.getGenericType();
            Type listType = genericType.getActualTypeArguments()[0];
            if (listType instanceof ParameterizedType) {
                ParameterizedType paraType = (ParameterizedType) listType;
                if ("java.util.Map".equals(((Class<?>)paraType.getRawType()).getName())) {
                    List<Map<String, String>> list = new ArrayList<Map<String, String>>();
                    for (int i = 0; i < arr.size(); i++) {
                        Map<String, String> classMap = new HashMap<String, String>();
                        Map<String, String> map = (Map<String, String>) JSONObject
                                .toBean(JSONObject.fromObject(arr.optString(i)),
                                        Map.class, classMap);
                        list.add(map);
                    }
                    field.set(bean, list);
                }
            } else if(List.class.isAssignableFrom(field.getType())){
                String argCalssName = listType.toString().substring(listType.toString().lastIndexOf(" ") + 1);
                Class<?> clazz = Class.forName(argCalssName);
                List<Object> list = new ArrayList<Object>();
                for (int index = 0; index < arr.size(); index++) {
                    Object element = arr.get(index);
                    if (clazz == element.getClass()) {
                        list.add(element);
                    } else {
                        Object obj = JSONObject.toBean(JSONObject.fromObject(arr.optString(index)), clazz);
                        list.add(obj);
                    }
                }
                field.set(bean, list);
            } else {
                field.set(bean, arr);
            }
        }

    }

    public static Field getFieldByName(Object obj, String key) {
        if (obj == null || key == null)
            return null;
        for (Class clazz = obj.getClass(); !clazz.getName().equals(Object.class.getName()); clazz = clazz
                .getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field f : fields) {
                if (f.getName().equals(key)) {
                    return f;
                }
            }
        }
        return null;

    }

    public static Field getFieldByNameIgnoreCase(Class<?> clazz, String key) {
        if (clazz == null || key == null)
            return null;
        for (; !clazz.getName().equals(Object.class.getName()); clazz = clazz
                .getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field f : fields) {
                if (f.getName().equalsIgnoreCase(key)) {
                    return f;
                }
            }
        }
        return null;

    }

    public static Object getFieldValueByNameIgnoreCase(Object obj, String key) {
        if (obj == null || key == null)
            return null;
        Class<? extends Object> clazz = obj.getClass();
        for (; !clazz.getName().equals(Object.class.getName()); clazz = clazz
                .getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field f : fields) {
                if (f.getName().equalsIgnoreCase(key)) {
                    f.setAccessible(true);
                    try {
                        return f.get(obj);
                    } catch (Exception e) {

                    }
                }
            }
        }
        return null;
    }

}
